﻿#ifndef AMO_TEMPLATE_MACRO_HPP__
#define AMO_TEMPLATE_MACRO_HPP__

 
#include <amo/functional.hpp>
#include <amo/nil.hpp>

#define COMMA0
#define COMMA1 ,
#define COMMA2 ,
#define COMMA3 ,
#define COMMA4 ,
#define COMMA5 ,
#define COMMA6 ,
#define COMMA7 ,
#define COMMA8 ,
#define COMMA9 ,
#define COMMA10 ,
#define COMMA11 ,
#define COMMA12 ,
#define COMMA13 ,
#define COMMA14 ,
#define COMMA15 ,
#define COMMA16 ,
#define COMMA17 ,
#define COMMA18 ,
#define COMMA19 ,
#define COMMA20 ,

#define VALID_PARAM_TYPE20 typedef P20 Param20; VALID_PARAM_TYPE19
#define VALID_PARAM_TYPE19 typedef P19 Param19; VALID_PARAM_TYPE18
#define VALID_PARAM_TYPE18 typedef P18 Param18; VALID_PARAM_TYPE17
#define VALID_PARAM_TYPE17 typedef P17 Param17; VALID_PARAM_TYPE16
#define VALID_PARAM_TYPE16 typedef P16 Param16; VALID_PARAM_TYPE15
#define VALID_PARAM_TYPE15 typedef P15 Param15; VALID_PARAM_TYPE14
#define VALID_PARAM_TYPE14 typedef P14 Param14; VALID_PARAM_TYPE13
#define VALID_PARAM_TYPE13 typedef P13 Param13; VALID_PARAM_TYPE12
#define VALID_PARAM_TYPE12 typedef P12 Param12; VALID_PARAM_TYPE11
#define VALID_PARAM_TYPE11 typedef P11 Param11; VALID_PARAM_TYPE10
#define VALID_PARAM_TYPE10 typedef P10 Param10; VALID_PARAM_TYPE9
#define VALID_PARAM_TYPE9 typedef P9 Param9; VALID_PARAM_TYPE8
#define VALID_PARAM_TYPE8 typedef P8 Param8; VALID_PARAM_TYPE7
#define VALID_PARAM_TYPE7 typedef P7 Param7; VALID_PARAM_TYPE6
#define VALID_PARAM_TYPE6 typedef P6 Param6; VALID_PARAM_TYPE5
#define VALID_PARAM_TYPE5 typedef P5 Param5; VALID_PARAM_TYPE4
#define VALID_PARAM_TYPE4 typedef P4 Param4; VALID_PARAM_TYPE3
#define VALID_PARAM_TYPE3 typedef P3 Param3; VALID_PARAM_TYPE2
#define VALID_PARAM_TYPE2 typedef P2 Param2; VALID_PARAM_TYPE1
#define VALID_PARAM_TYPE1 typedef P1 Param1; 
#define VALID_PARAM_TYPE0 

#define INVALID_PARAM_TYPE1 typedef void Param1; INVALID_PARAM_TYPE2
#define INVALID_PARAM_TYPE2 typedef void Param2; INVALID_PARAM_TYPE3
#define INVALID_PARAM_TYPE3 typedef void Param3; INVALID_PARAM_TYPE4
#define INVALID_PARAM_TYPE4 typedef void Param4; INVALID_PARAM_TYPE5
#define INVALID_PARAM_TYPE5 typedef void Param5; INVALID_PARAM_TYPE6
#define INVALID_PARAM_TYPE6 typedef void Param6; INVALID_PARAM_TYPE7
#define INVALID_PARAM_TYPE7 typedef void Param7; INVALID_PARAM_TYPE8
#define INVALID_PARAM_TYPE8 typedef void Param8; INVALID_PARAM_TYPE9
#define INVALID_PARAM_TYPE9 typedef void Param9; INVALID_PARAM_TYPE10
#define INVALID_PARAM_TYPE10 typedef void Param10; INVALID_PARAM_TYPE11
#define INVALID_PARAM_TYPE11 typedef void Param11; INVALID_PARAM_TYPE12
#define INVALID_PARAM_TYPE12 typedef void Param12; INVALID_PARAM_TYPE13
#define INVALID_PARAM_TYPE13 typedef void Param13; INVALID_PARAM_TYPE14
#define INVALID_PARAM_TYPE14 typedef void Param14; INVALID_PARAM_TYPE15
#define INVALID_PARAM_TYPE15 typedef void Param15; INVALID_PARAM_TYPE16
#define INVALID_PARAM_TYPE16 typedef void Param16; INVALID_PARAM_TYPE17
#define INVALID_PARAM_TYPE17 typedef void Param17; INVALID_PARAM_TYPE18
#define INVALID_PARAM_TYPE18 typedef void Param18; INVALID_PARAM_TYPE19
#define INVALID_PARAM_TYPE19 typedef void Param19; INVALID_PARAM_TYPE20
#define INVALID_PARAM_TYPE20 typedef void Param20;  
#define INVALID_PARAM_TYPE21   


#define FUNC_PARAM_TYPE0
#define FUNC_PARAM_TYPE1 P1
#define FUNC_PARAM_TYPE2 FUNC_PARAM_TYPE1, P2
#define FUNC_PARAM_TYPE3 FUNC_PARAM_TYPE2, P3
#define FUNC_PARAM_TYPE4 FUNC_PARAM_TYPE3, P4
#define FUNC_PARAM_TYPE5 FUNC_PARAM_TYPE4, P5
#define FUNC_PARAM_TYPE6 FUNC_PARAM_TYPE5, P6
#define FUNC_PARAM_TYPE7 FUNC_PARAM_TYPE6, P7
#define FUNC_PARAM_TYPE8 FUNC_PARAM_TYPE7, P8
#define FUNC_PARAM_TYPE9 FUNC_PARAM_TYPE8, P9
#define FUNC_PARAM_TYPE10 FUNC_PARAM_TYPE9, P10
#define FUNC_PARAM_TYPE11 FUNC_PARAM_TYPE10, P11
#define FUNC_PARAM_TYPE12 FUNC_PARAM_TYPE11, P12
#define FUNC_PARAM_TYPE13 FUNC_PARAM_TYPE12, P13
#define FUNC_PARAM_TYPE14 FUNC_PARAM_TYPE13, P14
#define FUNC_PARAM_TYPE15 FUNC_PARAM_TYPE14, P15
#define FUNC_PARAM_TYPE16 FUNC_PARAM_TYPE15, P16
#define FUNC_PARAM_TYPE17 FUNC_PARAM_TYPE16, P17
#define FUNC_PARAM_TYPE18 FUNC_PARAM_TYPE17, P18
#define FUNC_PARAM_TYPE19 FUNC_PARAM_TYPE18, P19
#define FUNC_PARAM_TYPE20 FUNC_PARAM_TYPE19, P20


#define TEMPLATE_PARAM_TYPE_PURE0 
#define TEMPLATE_PARAM_TYPE_PURE1 typename P1 
#define TEMPLATE_PARAM_TYPE_PURE2 TEMPLATE_PARAM_TYPE_PURE1, typename P2 
#define TEMPLATE_PARAM_TYPE_PURE3 TEMPLATE_PARAM_TYPE_PURE2, typename P3 
#define TEMPLATE_PARAM_TYPE_PURE4 TEMPLATE_PARAM_TYPE_PURE3, typename P4 
#define TEMPLATE_PARAM_TYPE_PURE5 TEMPLATE_PARAM_TYPE_PURE4, typename P5
#define TEMPLATE_PARAM_TYPE_PURE6 TEMPLATE_PARAM_TYPE_PURE5, typename P6
#define TEMPLATE_PARAM_TYPE_PURE7 TEMPLATE_PARAM_TYPE_PURE6, typename P7
#define TEMPLATE_PARAM_TYPE_PURE8 TEMPLATE_PARAM_TYPE_PURE7, typename P8
#define TEMPLATE_PARAM_TYPE_PURE9 TEMPLATE_PARAM_TYPE_PURE8, typename P9
#define TEMPLATE_PARAM_TYPE_PURE10 TEMPLATE_PARAM_TYPE_PURE9, typename P10
#define TEMPLATE_PARAM_TYPE_PURE11 TEMPLATE_PARAM_TYPE_PURE10, typename P11
#define TEMPLATE_PARAM_TYPE_PURE12 TEMPLATE_PARAM_TYPE_PURE11, typename P12
#define TEMPLATE_PARAM_TYPE_PURE13 TEMPLATE_PARAM_TYPE_PURE12, typename P13
#define TEMPLATE_PARAM_TYPE_PURE14 TEMPLATE_PARAM_TYPE_PURE13, typename P14
#define TEMPLATE_PARAM_TYPE_PURE15 TEMPLATE_PARAM_TYPE_PURE14, typename P15
#define TEMPLATE_PARAM_TYPE_PURE16 TEMPLATE_PARAM_TYPE_PURE15, typename P16
#define TEMPLATE_PARAM_TYPE_PURE17 TEMPLATE_PARAM_TYPE_PURE16, typename P17
#define TEMPLATE_PARAM_TYPE_PURE18 TEMPLATE_PARAM_TYPE_PURE17, typename P18
#define TEMPLATE_PARAM_TYPE_PURE19 TEMPLATE_PARAM_TYPE_PURE18, typename P19
#define TEMPLATE_PARAM_TYPE_PURE20 TEMPLATE_PARAM_TYPE_PURE19, typename P20


#define NORETURN_TEMPLATE_PARAM_TYPE0 
#define NORETURN_TEMPLATE_PARAM_TYPE1 typename P1 
#define NORETURN_TEMPLATE_PARAM_TYPE2 NORETURN_TEMPLATE_PARAM_TYPE1, typename P2 
#define NORETURN_TEMPLATE_PARAM_TYPE3 NORETURN_TEMPLATE_PARAM_TYPE2, typename P3 
#define NORETURN_TEMPLATE_PARAM_TYPE4 NORETURN_TEMPLATE_PARAM_TYPE3, typename P4 
#define NORETURN_TEMPLATE_PARAM_TYPE5 NORETURN_TEMPLATE_PARAM_TYPE4, typename P5
#define NORETURN_TEMPLATE_PARAM_TYPE6 NORETURN_TEMPLATE_PARAM_TYPE5, typename P6
#define NORETURN_TEMPLATE_PARAM_TYPE7 NORETURN_TEMPLATE_PARAM_TYPE6, typename P7
#define NORETURN_TEMPLATE_PARAM_TYPE8 NORETURN_TEMPLATE_PARAM_TYPE7, typename P8
#define NORETURN_TEMPLATE_PARAM_TYPE9 NORETURN_TEMPLATE_PARAM_TYPE8, typename P9
#define NORETURN_TEMPLATE_PARAM_TYPE10 NORETURN_TEMPLATE_PARAM_TYPE9, typename P10
#define NORETURN_TEMPLATE_PARAM_TYPE11 NORETURN_TEMPLATE_PARAM_TYPE10, typename P11
#define NORETURN_TEMPLATE_PARAM_TYPE12 NORETURN_TEMPLATE_PARAM_TYPE11, typename P12
#define NORETURN_TEMPLATE_PARAM_TYPE13 NORETURN_TEMPLATE_PARAM_TYPE12, typename P13
#define NORETURN_TEMPLATE_PARAM_TYPE14 NORETURN_TEMPLATE_PARAM_TYPE13, typename P14
#define NORETURN_TEMPLATE_PARAM_TYPE15 NORETURN_TEMPLATE_PARAM_TYPE14, typename P15
#define NORETURN_TEMPLATE_PARAM_TYPE16 NORETURN_TEMPLATE_PARAM_TYPE15, typename P16
#define NORETURN_TEMPLATE_PARAM_TYPE17 NORETURN_TEMPLATE_PARAM_TYPE16, typename P17
#define NORETURN_TEMPLATE_PARAM_TYPE18 NORETURN_TEMPLATE_PARAM_TYPE17, typename P18
#define NORETURN_TEMPLATE_PARAM_TYPE19 NORETURN_TEMPLATE_PARAM_TYPE18, typename P19
#define NORETURN_TEMPLATE_PARAM_TYPE20 NORETURN_TEMPLATE_PARAM_TYPE19, typename P20

#define TEMPLATE_PARAM_TYPE0 typename R
#define TEMPLATE_PARAM_TYPE1 TEMPLATE_PARAM_TYPE0, typename P1 
#define TEMPLATE_PARAM_TYPE2 TEMPLATE_PARAM_TYPE1, typename P2 
#define TEMPLATE_PARAM_TYPE3 TEMPLATE_PARAM_TYPE2, typename P3 
#define TEMPLATE_PARAM_TYPE4 TEMPLATE_PARAM_TYPE3, typename P4 
#define TEMPLATE_PARAM_TYPE5 TEMPLATE_PARAM_TYPE4, typename P5
#define TEMPLATE_PARAM_TYPE6 TEMPLATE_PARAM_TYPE5, typename P6
#define TEMPLATE_PARAM_TYPE7 TEMPLATE_PARAM_TYPE6, typename P7
#define TEMPLATE_PARAM_TYPE8 TEMPLATE_PARAM_TYPE7, typename P8
#define TEMPLATE_PARAM_TYPE9 TEMPLATE_PARAM_TYPE8, typename P9
#define TEMPLATE_PARAM_TYPE10 TEMPLATE_PARAM_TYPE9, typename P10
#define TEMPLATE_PARAM_TYPE11 TEMPLATE_PARAM_TYPE10, typename P11
#define TEMPLATE_PARAM_TYPE12 TEMPLATE_PARAM_TYPE11, typename P12
#define TEMPLATE_PARAM_TYPE13 TEMPLATE_PARAM_TYPE12, typename P13
#define TEMPLATE_PARAM_TYPE14 TEMPLATE_PARAM_TYPE13, typename P14
#define TEMPLATE_PARAM_TYPE15 TEMPLATE_PARAM_TYPE14, typename P15
#define TEMPLATE_PARAM_TYPE16 TEMPLATE_PARAM_TYPE15, typename P16
#define TEMPLATE_PARAM_TYPE17 TEMPLATE_PARAM_TYPE16, typename P17
#define TEMPLATE_PARAM_TYPE18 TEMPLATE_PARAM_TYPE17, typename P18
#define TEMPLATE_PARAM_TYPE19 TEMPLATE_PARAM_TYPE18, typename P19
#define TEMPLATE_PARAM_TYPE20 TEMPLATE_PARAM_TYPE19, typename P20


#define TEMPLATE_PARAM_MEN_TYPE0 typename R, typename C
#define TEMPLATE_PARAM_MEN_TYPE1 TEMPLATE_PARAM_MEN_TYPE0, typename P1 
#define TEMPLATE_PARAM_MEN_TYPE2 TEMPLATE_PARAM_MEN_TYPE1, typename P2 
#define TEMPLATE_PARAM_MEN_TYPE3 TEMPLATE_PARAM_MEN_TYPE2, typename P3 
#define TEMPLATE_PARAM_MEN_TYPE4 TEMPLATE_PARAM_MEN_TYPE3, typename P4 
#define TEMPLATE_PARAM_MEN_TYPE5 TEMPLATE_PARAM_MEN_TYPE4, typename P5
#define TEMPLATE_PARAM_MEN_TYPE6 TEMPLATE_PARAM_MEN_TYPE5, typename P6
#define TEMPLATE_PARAM_MEN_TYPE7 TEMPLATE_PARAM_MEN_TYPE6, typename P7
#define TEMPLATE_PARAM_MEN_TYPE8 TEMPLATE_PARAM_MEN_TYPE7, typename P8
#define TEMPLATE_PARAM_MEN_TYPE9 TEMPLATE_PARAM_MEN_TYPE8, typename P9
#define TEMPLATE_PARAM_MEN_TYPE10 TEMPLATE_PARAM_MEN_TYPE9, typename P10
#define TEMPLATE_PARAM_MEN_TYPE11 TEMPLATE_PARAM_MEN_TYPE10, typename P11
#define TEMPLATE_PARAM_MEN_TYPE12 TEMPLATE_PARAM_MEN_TYPE11, typename P12
#define TEMPLATE_PARAM_MEN_TYPE13 TEMPLATE_PARAM_MEN_TYPE12, typename P13
#define TEMPLATE_PARAM_MEN_TYPE14 TEMPLATE_PARAM_MEN_TYPE13, typename P14
#define TEMPLATE_PARAM_MEN_TYPE15 TEMPLATE_PARAM_MEN_TYPE14, typename P15
#define TEMPLATE_PARAM_MEN_TYPE16 TEMPLATE_PARAM_MEN_TYPE15, typename P16
#define TEMPLATE_PARAM_MEN_TYPE17 TEMPLATE_PARAM_MEN_TYPE16, typename P17
#define TEMPLATE_PARAM_MEN_TYPE18 TEMPLATE_PARAM_MEN_TYPE17, typename P18
#define TEMPLATE_PARAM_MEN_TYPE19 TEMPLATE_PARAM_MEN_TYPE18, typename P19
#define TEMPLATE_PARAM_MEN_TYPE20 TEMPLATE_PARAM_MEN_TYPE19, typename P20


#define FUNC_PARAM0
#define FUNC_PARAM1 P1 p1
#define FUNC_PARAM2 FUNC_PARAM1, P2 p2
#define FUNC_PARAM3 FUNC_PARAM2, P3 p3
#define FUNC_PARAM4 FUNC_PARAM3, P4 p4
#define FUNC_PARAM5 FUNC_PARAM4, P5 p5
#define FUNC_PARAM6 FUNC_PARAM5, P6 p6
#define FUNC_PARAM7 FUNC_PARAM6, P7 p7
#define FUNC_PARAM8 FUNC_PARAM7, P8 p8
#define FUNC_PARAM9 FUNC_PARAM8, P9 p9
#define FUNC_PARAM10 FUNC_PARAM9, P10 p10
#define FUNC_PARAM11 FUNC_PARAM10, P11 p11
#define FUNC_PARAM12 FUNC_PARAM11, P12 p12
#define FUNC_PARAM13 FUNC_PARAM12, P13 p13
#define FUNC_PARAM14 FUNC_PARAM13, P14 p14
#define FUNC_PARAM15 FUNC_PARAM14, P15 p15
#define FUNC_PARAM16 FUNC_PARAM15, P16 p16
#define FUNC_PARAM17 FUNC_PARAM16, P17 p17
#define FUNC_PARAM18 FUNC_PARAM17, P18 p18
#define FUNC_PARAM19 FUNC_PARAM18, P19 p19
#define FUNC_PARAM20 FUNC_PARAM19, P20 p20

#define FUNC_PARAM_REF0
#define FUNC_PARAM_REF1 const P1& p1
#define FUNC_PARAM_REF2 FUNC_PARAM_REF1,const P2& p2
#define FUNC_PARAM_REF3 FUNC_PARAM_REF2,const P3& p3
#define FUNC_PARAM_REF4 FUNC_PARAM_REF3,const P4& p4
#define FUNC_PARAM_REF5 FUNC_PARAM_REF4,const P5& p5
#define FUNC_PARAM_REF6 FUNC_PARAM_REF5,const P6& p6
#define FUNC_PARAM_REF7 FUNC_PARAM_REF6,const P7& p7
#define FUNC_PARAM_REF8 FUNC_PARAM_REF7,const P8& p8
#define FUNC_PARAM_REF9 FUNC_PARAM_REF8,const P9& p9
#define FUNC_PARAM_REF10 FUNC_PARAM_REF9,const P10& p10
#define FUNC_PARAM_REF11 FUNC_PARAM_REF10,const P11& p11
#define FUNC_PARAM_REF12 FUNC_PARAM_REF11,const P12& p12
#define FUNC_PARAM_REF13 FUNC_PARAM_REF12,const P13& p13
#define FUNC_PARAM_REF14 FUNC_PARAM_REF13,const P14& p14
#define FUNC_PARAM_REF15 FUNC_PARAM_REF14,const P15& p15
#define FUNC_PARAM_REF16 FUNC_PARAM_REF15,const P16& p16
#define FUNC_PARAM_REF17 FUNC_PARAM_REF16,const P17& p17
#define FUNC_PARAM_REF18 FUNC_PARAM_REF17,const P18& p18
#define FUNC_PARAM_REF19 FUNC_PARAM_REF18,const P19& p19
#define FUNC_PARAM_REF20 FUNC_PARAM_REF19,const P20& p20

#define FUNC_PARAM_VAL0
#define FUNC_PARAM_VAL1 p1
#define FUNC_PARAM_VAL2 FUNC_PARAM_VAL1, p2
#define FUNC_PARAM_VAL3 FUNC_PARAM_VAL2, p3
#define FUNC_PARAM_VAL4 FUNC_PARAM_VAL3, p4
#define FUNC_PARAM_VAL5 FUNC_PARAM_VAL4, p5
#define FUNC_PARAM_VAL6 FUNC_PARAM_VAL5, p6
#define FUNC_PARAM_VAL7 FUNC_PARAM_VAL6, p7
#define FUNC_PARAM_VAL8 FUNC_PARAM_VAL7, p8
#define FUNC_PARAM_VAL9 FUNC_PARAM_VAL8, p9
#define FUNC_PARAM_VAL10 FUNC_PARAM_VAL9, p10
#define FUNC_PARAM_VAL11 FUNC_PARAM_VAL10, p11
#define FUNC_PARAM_VAL12 FUNC_PARAM_VAL11, p12
#define FUNC_PARAM_VAL13 FUNC_PARAM_VAL12, p13
#define FUNC_PARAM_VAL14 FUNC_PARAM_VAL13, p14
#define FUNC_PARAM_VAL15 FUNC_PARAM_VAL14, p15
#define FUNC_PARAM_VAL16 FUNC_PARAM_VAL15, p16
#define FUNC_PARAM_VAL17 FUNC_PARAM_VAL16, p17
#define FUNC_PARAM_VAL18 FUNC_PARAM_VAL17, p18
#define FUNC_PARAM_VAL19 FUNC_PARAM_VAL18, p19
#define FUNC_PARAM_VAL20 FUNC_PARAM_VAL19, p20



#define EXPANDED_TEMPLATE_PARAM0
#define EXPANDED_TEMPLATE_PARAM1  typename GetParamsType<Functor>::Param1 p1
#define EXPANDED_TEMPLATE_PARAM2 EXPANDED_TEMPLATE_PARAM1, typename GetParamsType<Functor>::Param2 p2
#define EXPANDED_TEMPLATE_PARAM3 EXPANDED_TEMPLATE_PARAM2, typename GetParamsType<Functor>::Param3 p3
#define EXPANDED_TEMPLATE_PARAM4 EXPANDED_TEMPLATE_PARAM3, typename GetParamsType<Functor>::Param4 p4
#define EXPANDED_TEMPLATE_PARAM5 EXPANDED_TEMPLATE_PARAM4, typename GetParamsType<Functor>::Param5 p5
#define EXPANDED_TEMPLATE_PARAM6 EXPANDED_TEMPLATE_PARAM5, typename GetParamsType<Functor>::Param6 p6
#define EXPANDED_TEMPLATE_PARAM7 EXPANDED_TEMPLATE_PARAM6, typename GetParamsType<Functor>::Param7 p7
#define EXPANDED_TEMPLATE_PARAM8 EXPANDED_TEMPLATE_PARAM7, typename GetParamsType<Functor>::Param8 p8
#define EXPANDED_TEMPLATE_PARAM9 EXPANDED_TEMPLATE_PARAM8, typename GetParamsType<Functor>::Param9 p9
#define EXPANDED_TEMPLATE_PARAM10 EXPANDED_TEMPLATE_PARAM9, typename GetParamsType<Functor>::Param10 p10
#define EXPANDED_TEMPLATE_PARAM11 EXPANDED_TEMPLATE_PARAM10, typename GetParamsType<Functor>::Param11 p11
#define EXPANDED_TEMPLATE_PARAM12 EXPANDED_TEMPLATE_PARAM11, typename GetParamsType<Functor>::Param12 p12
#define EXPANDED_TEMPLATE_PARAM13 EXPANDED_TEMPLATE_PARAM12, typename GetParamsType<Functor>::Param13 p13
#define EXPANDED_TEMPLATE_PARAM14 EXPANDED_TEMPLATE_PARAM13, typename GetParamsType<Functor>::Param14 p14
#define EXPANDED_TEMPLATE_PARAM15 EXPANDED_TEMPLATE_PARAM14, typename GetParamsType<Functor>::Param15 p15
#define EXPANDED_TEMPLATE_PARAM16 EXPANDED_TEMPLATE_PARAM15, typename GetParamsType<Functor>::Param16 p16
#define EXPANDED_TEMPLATE_PARAM17 EXPANDED_TEMPLATE_PARAM16, typename GetParamsType<Functor>::Param17 p17
#define EXPANDED_TEMPLATE_PARAM18 EXPANDED_TEMPLATE_PARAM17, typename GetParamsType<Functor>::Param18 p18
#define EXPANDED_TEMPLATE_PARAM19 EXPANDED_TEMPLATE_PARAM18, typename GetParamsType<Functor>::Param19 p19
#define EXPANDED_TEMPLATE_PARAM20 EXPANDED_TEMPLATE_PARAM19, typename GetParamsType<Functor>::Param20 p20

template< typename T/*, typename U */>
struct GetParamsType;


#define GET_FUNC_PARAM_TYPE(val, next)\
	template<TEMPLATE_PARAM_TYPE##val >\
struct GetParamsType< R( FUNC_PARAM_TYPE##val) >\
{\
	typedef R	 Result;\
	VALID_PARAM_TYPE##val\
	INVALID_PARAM_TYPE##next\
	typedef amo::function<R(FUNC_PARAM_TYPE##val)> type;\
};\

#define GET_FUNC_PTR_PARAM_TYPE(val, next)\
	template<TEMPLATE_PARAM_TYPE##val >\
struct GetParamsType< R(*)( FUNC_PARAM_TYPE##val) >\
{\
	typedef R	 Result;\
	VALID_PARAM_TYPE##val\
	INVALID_PARAM_TYPE##next\
	typedef amo::function<R(FUNC_PARAM_TYPE##val)> type;\
};\

#define GET_MEN_FUNC_PARAM_TYPE(val, next)\
	template<TEMPLATE_PARAM_MEN_TYPE##val >\
struct GetParamsType< R(C::*)( FUNC_PARAM_TYPE##val) >\
{\
	typedef R	 Result;\
	VALID_PARAM_TYPE##val\
	INVALID_PARAM_TYPE##next\
	typedef amo::function<R(FUNC_PARAM_TYPE##val)> type;\
};\



	GET_FUNC_PARAM_TYPE(0,1)
	GET_FUNC_PARAM_TYPE(1,2)
	GET_FUNC_PARAM_TYPE(2,3)
	GET_FUNC_PARAM_TYPE(3,4)
	GET_FUNC_PARAM_TYPE(4,5)
	GET_FUNC_PARAM_TYPE(5,6)
	GET_FUNC_PARAM_TYPE(6,7)
	GET_FUNC_PARAM_TYPE(7,8)
	GET_FUNC_PARAM_TYPE(8,9)
	GET_FUNC_PARAM_TYPE(9,10)
	GET_FUNC_PARAM_TYPE(10,11)
	GET_FUNC_PARAM_TYPE(11,12)
	GET_FUNC_PARAM_TYPE(12,13)
	GET_FUNC_PARAM_TYPE(13,14)
	GET_FUNC_PARAM_TYPE(14,15)
	GET_FUNC_PARAM_TYPE(15,16)
	GET_FUNC_PARAM_TYPE(16,17)
	GET_FUNC_PARAM_TYPE(17,18)
	GET_FUNC_PARAM_TYPE(18,19)
	GET_FUNC_PARAM_TYPE(19,20)
	GET_FUNC_PARAM_TYPE(20,21)



	GET_FUNC_PTR_PARAM_TYPE(0,1)
	GET_FUNC_PTR_PARAM_TYPE(1,2)
	GET_FUNC_PTR_PARAM_TYPE(2,3)
	GET_FUNC_PTR_PARAM_TYPE(3,4)
	GET_FUNC_PTR_PARAM_TYPE(4,5)
	GET_FUNC_PTR_PARAM_TYPE(5,6)
	GET_FUNC_PTR_PARAM_TYPE(6,7)
	GET_FUNC_PTR_PARAM_TYPE(7,8)
	GET_FUNC_PTR_PARAM_TYPE(8,9)
	GET_FUNC_PTR_PARAM_TYPE(9,10)
	GET_FUNC_PTR_PARAM_TYPE(10,11)
	GET_FUNC_PTR_PARAM_TYPE(11,12)
	GET_FUNC_PTR_PARAM_TYPE(12,13)
	GET_FUNC_PTR_PARAM_TYPE(13,14)
	GET_FUNC_PTR_PARAM_TYPE(14,15)
	GET_FUNC_PTR_PARAM_TYPE(15,16)
	GET_FUNC_PTR_PARAM_TYPE(16,17)
	GET_FUNC_PTR_PARAM_TYPE(17,18)
	GET_FUNC_PTR_PARAM_TYPE(18,19)
	GET_FUNC_PTR_PARAM_TYPE(19,20)
	GET_FUNC_PTR_PARAM_TYPE(20,21)

	GET_MEN_FUNC_PARAM_TYPE(0,1)
	GET_MEN_FUNC_PARAM_TYPE(1,2)
	GET_MEN_FUNC_PARAM_TYPE(2,3)
	GET_MEN_FUNC_PARAM_TYPE(3,4)
	GET_MEN_FUNC_PARAM_TYPE(4,5)
	GET_MEN_FUNC_PARAM_TYPE(5,6)
	GET_MEN_FUNC_PARAM_TYPE(6,7)
	GET_MEN_FUNC_PARAM_TYPE(7,8)
	GET_MEN_FUNC_PARAM_TYPE(8,9)
	GET_MEN_FUNC_PARAM_TYPE(9,10)
	GET_MEN_FUNC_PARAM_TYPE(10,11)
	GET_MEN_FUNC_PARAM_TYPE(11,12)
	GET_MEN_FUNC_PARAM_TYPE(12,13)
	GET_MEN_FUNC_PARAM_TYPE(13,14)
	GET_MEN_FUNC_PARAM_TYPE(14,15)
	GET_MEN_FUNC_PARAM_TYPE(15,16)
	GET_MEN_FUNC_PARAM_TYPE(16,17)
	GET_MEN_FUNC_PARAM_TYPE(17,18)
	GET_MEN_FUNC_PARAM_TYPE(18,19)
	GET_MEN_FUNC_PARAM_TYPE(19,20)
	GET_MEN_FUNC_PARAM_TYPE(20,21)

	template<typename T>
	struct GetValueType
	{
		typedef T value_type;
	};

	template<>
	struct GetValueType <void>
	{
		typedef amo::nil type;
	};

	template<typename T>
	struct Void2Nil
	{
		typedef T value_type;
	};

	template<>
	struct Void2Nil < void >
	{
		typedef amo::nil type;
	};

	template<typename T>
	struct Nil2Void
	{
		typedef T value_type;
	};

	template<>
	struct Nil2Void < amo::nil >
	{
		typedef void type;
	};

#endif // AMO_TEMPLATE_MACRO_HPP__
